因為我的 devel env 跟實際 production env 有太多的不同,所以我實際 deploy 的時候經常會出現一堆奇怪的問題。這邊會嘗試不定期記錄下來我找到的各種暴力解法。
其中最近困擾我的就是這個:
django.db.utils.OperationalError: 3780 Referencing column and referenced column are incompatible
這個主因其實是我 devel 跟 production 的 Django 版本不一樣,當然有很多因素讓我選擇不同步(因為連作業系統都不一樣了),而這是一個很常見的 Error.
這個常見的因素是使用 ForeignKey 的時候, primary_key 有的版本或作業系統使用 BigAutoField 而有些使用 AutoField ,而在某些 DB 版本中,這兩個會在 create table 時分別實作為 bigint 跟 int,而這個就是產生這個 Error 的主因。
ForeignKey 在實際使用時(假設叫做 xxx),會在 table 內建立一個 xxx_id ,而這個會去參照 ForeignKey 參照的 model 的 primary_key 。而如果兩邊的 Django 版本不同的話就很容易 raise 3780 出來。
解法其實很簡單,首先找出出錯的 migrations ,執行
python3 manage.py sqlmigrate <APP Name> <migration>
這個時候會出現一堆 SQL 指令,然後再執行
python3 manage.py dbshell
開始執行 sqlmigrate 得到的指令看是哪一行出錯,找出出錯的一行去 alter 成正確的就行了。
例如說假如 xxx 的 id 是 int auto_increment not null ,但是 ForeignKey 產生出來的 xxx_id 卻是 bigint default null 的時候,那就執行:
alter table <table_name> modify column xxx_id int Default NULL;
就可以了。
然後如果出錯的欄位後面還有其他 SQL commands 記得執行完。
最後因為其實已經在 database level 執行完了,所以可以直接把這個有問題的 migration fake 掉。
python3 manage.py sqlmigrate <APP Name> <migration> --fake
好了,暴力解完。雖然沒有解決根本問題但是至少可以不用被這個問題擋住開發。